using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Perovich.GameObjects.Interfaces;

namespace Perovich.GameObjects
{
    /// <summary>
    /// Provides data for a Collision event.
    /// </summary>
    public class CollisionEventArgs : EventArgs
    {
        private object other;

        /// <summary>
        /// The object that was collided with.
        /// </summary>
        public object Other
        {
            get { return other; }
            set { other = value; }
        }

        /// <summary>
        /// Constructs a new <see cref="CollisionEventArgs"/> instance.
        /// </summary>
        /// <param name="value"></param>
        public CollisionEventArgs(object value)
        {
            other = value;
        }
    }

    /// <summary>
    /// Static class containing helper functions for the <see cref="Perovich.GameObjects.Components"/> namespace.
    /// </summary>
    public static class ComponentsExtensions
    {

        /// <summary>
        /// Gets the angle between two <see cref="Vector2"/>s.
        /// </summary>
        /// <param name="alpha"></param>
        /// <param name="beta"></param>
        /// <returns></returns>
        public static float AngleBetween(Vector2 alpha, Vector2 beta)
        {
            return (float)Math.Acos(Vector2.Dot(Vector2.Normalize(alpha), Vector2.Normalize(beta))); ;
        }

        /// <summary>
        /// Gets the direction of a given <see cref="Vector2"/>.
        /// </summary>
        /// <param name="alpha"></param>
        /// <returns></returns>
        public static float GetDirection(Vector2 alpha)
        {
            float ret = AngleBetween(alpha, Vector2.UnitX);
            if (alpha.Y > 0)
                ret = MathHelper.TwoPi - ret;
            return ret;
        }

        internal static HashSet<IHelper> Helpers = new HashSet<IHelper>();

        internal static void ResetHelpers()
        {
            /*GestureHelper.Reset();
            KeyboardHelper.Reset();
            ParticleManager.Reset();
            GameStateManager.Reset();
            MouseHelper.Reset();*/
            foreach (IHelper hlp in Helpers)
            {
                hlp.Reset();
            }
        }

        /// <summary>
        /// Tells all <see cref="GameObject"/> objects in the <see cref="Interfaces.ICanHoldComponents"/> to check their collision tables for collisions.
        /// </summary>
        internal static void CheckColisions(ICanHoldComponents game)
        {
            foreach (object comp in game.Components)
            {
                ICollidable collide = comp as ICollidable;
                if (collide != null)
                {
                    collide.CheckCollisions();
                }
            }
        }

        internal static void CheckColisions(ComponentCollection comps)
        {
            foreach (object comp in comps)
            {
                ICollidable collide = comp as ICollidable;
                if (collide != null)
                {
                    collide.CheckCollisions();
                }
            }
        }



        private static Random random = new Random();

        /// <summary>
        /// Returns a random <see cref="Single"/> between the two given <see cref="Single"/>s.
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static float RandomBetween(float min, float max)
        {
            return min + (float)random.NextDouble() * (max - min);
        }



        public static int Top(this BoundingBox me)
        {
            return (int)me.Min.Y;
        }

        public static int Bottom(this BoundingBox me)
        {
            return (int)me.Max.Y;
        }
        public static int Left(this BoundingBox me)
        {
            return (int)me.Min.X;
        }
        public static int Right(this BoundingBox me)
        {
            return (int)me.Max.X;
        }
        public static int Width(this BoundingBox me)
        {
            return me.Right() - me.Left();
        }
    }
}
